package cn.com.cifi.mars.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.multipart.MultipartFile;

import cn.com.cifi.mars.common.base.MyThrow;
import cn.com.cifi.mars.constant.Constants;
import lombok.extern.slf4j.Slf4j;
/**
 * 
 * @author Administrator
 *
 */
@Slf4j
public class FileUtils {

	private static final String FILE_NAME_COMPLIANCE_REPLACEMENT= "_";

	@Value("${file.uploadFolder}")
	private String uploadFolder;

	@Value("${file.staticAccessPath}")
	private String staticAccessPath;
	
	public static boolean isWindows() {
		return '\\' == File.separatorChar;
	}
	
	/**
	 * 读取文件内容
	 * @param filePath
	 * @return
	 */
	public String read(String filePath) {
		String line = null;
		StringBuilder buf = new StringBuilder();
		// 根据文件路径创建缓冲输入流
		try(BufferedReader br = new BufferedReader(new FileReader(filePath))) {
			// 循环读取文件的每一行,放入缓冲对象中
			while ((line = br.readLine()) != null) {
				buf.append(line);
			}
		} catch (Exception e) {
			log.error(e.getMessage());
		} 
		return buf.toString();
	}
	
	/**
	 * 将内容写到文件中
	 * @param filePath
	 * @param content
	 */
	public void write(String filePath, String content) {
		// 根据文件路径创建缓冲输出流
		try(BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))) {
			// 将内容写入文件中
			bw.write(content);
		} catch (Exception e) {
			log.error(e.getMessage());
		}
	}

	
	/**
	 * 上传文件
	 * @param file
	 * @return
	 */
	public Map<String, Object> fileUploadToLocal(MultipartFile file) {
		Map<String, Object> jsonMap = new HashMap<>(16);
		try {
			//获取文件名
			String fileName = file.getOriginalFilename();

			//获取文件后缀
			String fileSuffix = fileName.substring(fileName.lastIndexOf('.'), fileName.length());

			//文件重命名
			String fileEnd = System.currentTimeMillis() + "";
			String uploadFileName = fileEnd + fileSuffix;

			//创建文件
			String uploadFileStr = uploadFolder + "/" + uploadFileName;
			File uploadFile = new File(uploadFileStr);
			//上传
			file.transferTo(uploadFile);

			jsonMap.put("success", true);
			//上传前文件名称
			jsonMap.put("accessName", uploadFileName);
			//绝对路径
			jsonMap.put("realPath", uploadFolder);
			//虚拟路径
			jsonMap.put("accessUrl", staticAccessPath.replace("**", "")+uploadFileName);
		} catch (Exception e) {
			jsonMap.put("success", false);
			jsonMap.put("error",e.getMessage());
			log.error("上传文件异常",e);
		}
		return jsonMap;
	}
	
	
	/**
	 * 创建文件夹
	 * @param dirName
	 * @return
	 */
	public static boolean creatDir(String dirName) {
		File dir = new File(dirName);
		if (dir.exists()) {
			log.info("创建目录" + dirName + "失败，目标目录已经存在");
			return false;
		}
		if (!dirName.endsWith(File.separator)) {
			dirName = dirName + File.separator;
		}
		// 创建目录
		if (dir.mkdirs()) {
			log.info("创建目录" + dirName + "成功！");
			return true;
		} else {
			log.info("创建目录" + dirName + "失败！");
			return false;
		}
	}
	
	
	/**
	 * 创建文件
	 * @param fileName
	 * @return
	 */
	public static boolean createFile(String fileName) {
		File file = new File(fileName);
		if (file.exists()) {
			log.info(Constants.CREATE_ONE_FILE + fileName + "失败，目标文件已存在！");
			return false;
		}
		if (fileName.endsWith(File.separator)) {
			log.info(Constants.CREATE_ONE_FILE + fileName + "失败，目标文件不能为目录！");
			return false;
		}
		// 判断目标文件所在的目录是否存在
		if (!file.getParentFile().exists()) {
			// 如果目标文件所在的目录不存在，则创建父目录
			log.info("目标文件所在目录不存在，准备创建它！");
			if (!file.getParentFile().mkdirs()) {
				log.info("创建目标文件所在目录失败！");
				return false;
			}
		}
		// 创建目标文件
		try {
			if (file.createNewFile()) {
				log.info(Constants.CREATE_ONE_FILE + fileName + "成功！");
				return true;
			} else {
				log.info(Constants.CREATE_ONE_FILE + fileName + "失败！");
				return false;
			}
		} catch (IOException e) {
			log.info(Constants.CREATE_ONE_FILE + fileName + "失败！" + e.getMessage());
			return false;
		}
	}
	
	/**
	 * 
	  * Desc：删除单个文件 
	  * @param filePath  被删除文件path 
	  * @return 删除成功返回true，否则返回false 
	  * @version v1.0
	  * @author yyd 2018年4月26日
	  *
	 */
	public static boolean deleteFile(String filePath) {  
	    File file = new File(filePath);  
	    // 路径为文件且不为空则进行删除  
	    if (file.isFile() && file.exists()) {  
	        try {
				Files.delete(file.toPath());
				return true;
			} catch (IOException e) {
				log.error(e.getMessage());
			}
	    }  
	    return false;  
	} 
	/**
	 *  
	  * Desc：删除目录以及目录下的文件
	  * @param dirPath 被删除目录的路径
	  * @return 目录删除成功返回true，否则返回false 
	  * @version v1.0
	  * @author yyd 2018年4月26日
	  *
	 */
	public static boolean deleteDirectory(String dirPath) {  
	    //如果dirPath不以文件分隔符结尾，自动添加文件分隔符  
	    if (!dirPath.endsWith(File.separator)) {  
	    	dirPath = dirPath + File.separator;  
	    }  
	    File dirFile = new File(dirPath);  
	    //如果dir对应的文件不存在，或者不是一个目录，则退出  
	    if (!dirFile.exists() || !dirFile.isDirectory()) {  
	        return false;  
	    }  
	    boolean flag = true;  
	    //删除文件夹下的所有文件(包括子目录)  
	    File[] files = dirFile.listFiles();  
	    for (int i = 0; i < files.length; i++) {  
	        //删除子文件  
	        if (files[i].isFile()) {  
	            flag = deleteFile(files[i].getAbsolutePath());  
	            if (!flag) { break;}  
	        } //删除子目录  
	        else {  
	            flag = deleteDirectory(files[i].getAbsolutePath());  
	            if (!flag) {break;}  
	        }  
	    }  
	    if (!flag) {return false;}  
	    //删除当前目录  
	    try {
			Files.delete(dirFile.toPath());
			return true;
		} catch (IOException e) {
			log.error(e.getMessage());
		}
	    return false;
	} 
	/**
	 * 
	  * Desc：根据路径删除指定的目录，无论存在与否 
	  * @param sPath 要删除的目录path 
	  * @return 删除成功返回 true，否则返回 false。 
	  * @version v1.0
	  * @author yyd 2018年4月26日
	  *
	 */
	public static boolean deleteFolder(String sPath) {  
	    boolean flag = false;  
	    File file = new File(sPath);  
	    // 判断目录或文件是否存在  
	    // 不存在返回 false
	    if (!file.exists()) {   
	        return flag;  
	    } else {  
	        // 判断是否为文件  
	    	// 为文件时调用删除文件方法
	        if (file.isFile()) {    
	            return deleteFile(sPath);  
	        } else {  
	        	// 为目录时调用删除目录方法  
	            return deleteDirectory(sPath);  
	        }  
	    }  
	}
	
	/**
	 * 压缩文件
	 * @param srcFilePath
	 * @param destFilePath
	 * @return
	 * @throws MyThrow 
	 */
	public static File compress(String srcFilePath, String destFilePath) throws MyThrow {
        File src = new File(srcFilePath);
        if (!src.exists()) {
            throw new MyThrow(srcFilePath + "不存在");
        }
        File zipFile = new File(destFilePath);
        try(FileOutputStream fos = new FileOutputStream(zipFile);
        	ZipOutputStream zos = new ZipOutputStream(fos);) {
            String baseDir = "";
            compressbyType(src, zos, baseDir);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return zipFile;
    }
	
	private static void compressbyType(File src, ZipOutputStream zos,String baseDir) {
        if (!src.exists()) {
        	return;
        }
        //判断文件是否是文件，如果是文件调用compressFile方法,如果是路径，则调用compressDir方法；
        if (src.isFile()) {
            //src是文件，调用此方法
            compressFile(src, zos, baseDir);
        } else if (src.isDirectory()) {
            //src是文件夹，调用此方法
            compressDir(src, zos, baseDir);
        }

    }
	
	private static void compressFile(File file, ZipOutputStream zos,String baseDir) {
        if (!file.exists()) {
        	return;
        }
        try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));) {
            ZipEntry entry = new ZipEntry(baseDir + file.getName());
            zos.putNextEntry(entry);
            int count;
            byte[] buf = new byte[1024];
            while ((count = bis.read(buf)) != -1) {
                zos.write(buf, 0, count);
            }
        } catch (Exception e) {
       	  log.error(e.getMessage());
        }
    }
	 
	 private static void compressDir(File dir, ZipOutputStream zos,String baseDir) {
        if (!dir.exists()) {
        	 return;
        }
        File[] files = dir.listFiles();
        if(files.length == 0){
            try {
                zos.putNextEntry(new ZipEntry(baseDir + dir.getName()+File.separator));
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
        for (File file : files) {
            compressbyType(file, zos, baseDir + dir.getName() + File.separator);
        }
	 }
	 
	 public static void inputStreamToFile(InputStream ins, File file) {  
		try (OutputStream os = new FileOutputStream(file);) {
			int bytesRead = 0;
			byte[] buffer = new byte[8192];
			while ((bytesRead = ins.read(buffer, 0, Constants.EIGHT_ONE_NINE_TWO)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
		} catch (Exception e) {
			log.error(e.getMessage());
		}
	}

	/**
	 * 文件名合规替换
	 * @param filename
	 * @return
	 */
	public static String complianceFileName(String filename){
		return filename.replaceAll("[/\\\\><\\?\\*\\|:\"]", FILE_NAME_COMPLIANCE_REPLACEMENT);
	}


		 
	
}
